#region using

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint;
using PS.Practices.Provisioner;
using PS.Practices.SiteBuilder.Features.API;
using PS.Practices.Util;
using Microsoft.SharePoint.Utilities;



#endregion

namespace PS.Practices.SiteBuilder.Features.Schema.DOM
{
    public abstract class WebOperation
    {
        public abstract void Execute(SPWeb web);
    }

    public abstract class ListOperation
    {
        public abstract void Execute(SPWeb web, SPList list);
    }

    public class FixupLists
        : WebOperation
    {
        private bool syncCTypeLocalFieldSettings;
        private List<List> lists = new List<List>();

        
        public bool SyncCTypeLocalFieldSettings
        {
            get { return syncCTypeLocalFieldSettings; }
            set { syncCTypeLocalFieldSettings = value; }
        }

        [XmlAttribute("SyncCTypeLocalFieldSettings")]
        public string SyncCTypeLocalFieldSettingsStr
        {
            get { return syncCTypeLocalFieldSettings.ToString(); }
            set { syncCTypeLocalFieldSettings = bool.Parse(value); }
        }

        [XmlElement("List")]
        public List<List> Lists
        {
            get { return lists; }
            set { lists = value; }
        }

        public override void Execute(SPWeb web)
        {
            if (SyncCTypeLocalFieldSettings)
            {
                try
                {
                    ListUtil.SyncReqHidFieldStatusInLists(web);
                }
                catch (Exception e)
                {
                    Logger.Error(e);
                }
            }

            foreach (List list in lists)
            {
                if(!string.IsNullOrEmpty(list.Title))
                {
                    SPList spList = null;
                    try
                    {
                        spList = web.Lists[list.Title];
                    }
                    catch (IndexOutOfRangeException)
                    { }
                    catch (ArgumentException)
                    { }

                    if (spList != null)
                    {
                        list.Process(spList);
                    }
                }
            }
        }
    }

    public class List
    {
        private bool enableContentTypes;
        private string emailEnable;
        private List<ListOperation> operations = new List<ListOperation>();

        public List()
        {
            Template = 100;
        }

        [XmlAttribute()]
        public string Title { get; set; }

        [XmlAttribute()]
        public int Template { get; set; }

        [XmlAttribute()]
        public string Description { get; set; }

        [XmlAttribute()]
        public bool Delete { get; set; }

        [XmlAttribute()]
        public bool EnableContentTypes
        {
            get { return enableContentTypes; }
            set { enableContentTypes = value; }
        }

        [XmlElement(typeof(SetSendToLocation))]
        [XmlElement(typeof(UpdateTitle))]
        [XmlElement(typeof(ReorderCTypes))]
        [XmlElement(typeof(FixupACL))]
        [XmlElement(typeof(FixupView))]
        [XmlElement(typeof(UpdateFields))]
        [XmlElement(typeof(AddFields))]
        [XmlElement(typeof(ListItem))]
        [XmlElement(typeof(AddCTypes))]
        [XmlElement(typeof(RemoveCTypes))]
        public List<ListOperation> Operations
        {
            get { return operations; }
            set { operations = value; }
        }

        [XmlAttribute("EMailEnable")]
        public string EmailEnable
        {
            get { return emailEnable; }
            set { emailEnable = value; }
        }

        [XmlAttribute("MajorVersionLimit")]
        public int MajorVersionLimit
        {
            get; set;
        }
        [XmlAttribute("MinorVersionLimit")]
        public int MinorVersionLimit
        {
            get; set;
        }
        [XmlAttribute("DraftSecurity")]
        public string DraftSecurity
        {
            get; set;
        }
        public void Process(SPList spList)
        {
#if !SANDBOX
            SPUtility.ValidateFormDigest();
            SPSecurity.RunWithElevatedPrivileges(delegate()
            {
#endif
                SPWeb web = spList.ParentWeb;
                
                web.AllowUnsafeUpdates = true;
                   
                Logger.Info("Processing list " + spList.Title);

                if (Delete)
                {

                    spList.AllowDeletion = true;
                    spList.Update();
                    spList.Delete();
                    //web.Update();
                    Logger.Info("List deleted");
                    return;
                }

                if (!string.IsNullOrEmpty(EmailEnable))
                {
                    try
                    {
                        string alias = ParserUtil.ReplaceLiveFields(EmailEnable, spList, web);
                        spList.EmailAlias = alias;
                        spList.Update();

                        SPFolder folder = spList.RootFolder;
                        folder.Properties["vti_emailattachmentfolders"] = "root";
                        folder.Properties["vti_emailsaveoriginal"] = 1;
                        folder.Properties["vti_emailusesecurity"] = 1;

                        folder.Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error Email Enabling: " + Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                        web.AllowUnsafeUpdates = false;
                    }
                }
                if (!string.IsNullOrEmpty(MajorVersionLimit.ToString()) && MajorVersionLimit > 0)
                {
                    try
                    {
                        //string alias = ParserUtil.ReplaceLiveFields(EmailEnable, spList, web);
                        spList.EnableVersioning = true;
                        spList.MajorVersionLimit = MajorVersionLimit;
                        spList.Update();


                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error Email Enabling: " + Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                        web.AllowUnsafeUpdates = false;
                    }
                }
                if (!string.IsNullOrEmpty(MinorVersionLimit.ToString()) && MinorVersionLimit > 0)
                {
                    try
                    {
                        if (spList.EnableVersioning == false)
                            spList.EnableVersioning = true;
                        spList.EnableMinorVersions = true;
                        spList.MajorWithMinorVersionsLimit = MinorVersionLimit;
                        spList.Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error MinorVersionLimit: " + Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                    }
                }
                if (!string.IsNullOrEmpty(DraftSecurity))
                {
                    try
                    {
                        if (string.Compare(DraftSecurity, "any",true) == 0)
                        {
                            spList.DraftVersionVisibility = DraftVisibilityType.Reader;
                        }
                        if (string.Compare(DraftSecurity, "author", true) == 0)
                        {
                            spList.DraftVersionVisibility = DraftVisibilityType.Author;
                        }
                        spList.Update();
                    }
                    catch (Exception ex)
                    {
                        Logger.Info("Error DraftSecurity: " + Title);
                        Logger.Error(ex);
                        spList.EmailAlias = string.Empty;
                    }
                }
                try
                {
                    spList.ContentTypesEnabled = EnableContentTypes;
                    Logger.Info("Setting list attribute EnableContentTypes = " + EnableContentTypes);
                    spList.Update();
                }
                catch (Exception e)
                {
                    Logger.Info("Setting list attribute EnableContentTypes = " + e.Message);
                        
                }
                  
                    

                foreach (ListOperation listOperation in operations)
                {
                    listOperation.Execute(web, spList);
                }
                web.AllowUnsafeUpdates = false;

#if !SANDBOX
            });
#endif
        }
    }

    public class SetSendToLocation
        : ListOperation
    {
        private string name;
        private string url;

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlAttribute()]
        public string Url
        {
            get { return url; }
            set { url = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            if (string.IsNullOrEmpty(Name))
            {
                Logger.Info("Required attribute Name is missing");
                return;
            }

            if (string.IsNullOrEmpty(Url))
            {
                Logger.Info("Required attribute Url is missing");
                return;
            }

            Url = ParserUtil.ReplaceLiveFields(Url, web);
            if (Url.StartsWith("./"))
            {
                Url = web.Url + Url.Substring(2);
            }
            else
            {
                if (Url.StartsWith("~/"))
                {
                    SPWeb rootWeb = web.Site.RootWeb;
                    Url = rootWeb.Url.TrimEnd('/') + Url.Substring(1);
                }
            }

            list.SendToLocationName = Name;
            list.SendToLocationUrl = Url;

            list.Update();
        }
    }

    public class Replace
    {
        private string match;
        private string value;

        [XmlAttribute()]
        public string Match
        {
            get { return match; }
            set { match = value; }
        }

        [XmlText()]
        public string Value
        {
            get { return value; }
            set { this.value = value; }
        }
    }

    public class UpdateTitle
        : ListOperation
    {
        private string set;
        private List<Replace> replaceInfo = new List<Replace>();

        //TODO: Possibly Set is excess
        [XmlAttribute()]
        public string Set
        {
            get { return set; }
            set { set = value; }
        }

        [XmlElement("Replace")]
        public List<Replace> ReplaceInfo
        {
            get { return replaceInfo; }
            set { replaceInfo = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();

            if (!string.IsNullOrEmpty(set))
            {
                list.Title = ParserUtil.ReplaceLiveFields(set, list, web);
            }
            else
            {
                foreach (Replace replace in replaceInfo)
                {
                    dic.Add(replace.Match, replace.Value);
                }

                ParserUtil.UpdateListTitle(list, null, dic);
            }
            list.Update();
        }
    }

    public class ContentTypeRef
    {
        private string id;
        private string name;

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlAttribute()]
        public string ID
        {
            get { return id; }
            set { id = value; }
        }
    }

    public abstract class ListCTypeOperation
        : ListOperation
    {
        private List<ContentTypeRef> contentTypes = new List<ContentTypeRef>();

        [XmlElement("ContentTypeRef")]
        public List<ContentTypeRef> ContentTypes
        {
            get { return contentTypes; }
            set { contentTypes = value; }
        }
    }

    public class AddCTypes
        : ListCTypeOperation
    {
        public override void Execute(SPWeb web, SPList list)
        {
            foreach (ContentTypeRef contentType in ContentTypes)
            {
                if (!string.IsNullOrEmpty(contentType.ID))
                    ListUtil.AddCType(list, contentType.ID);
                else
                    if (!string.IsNullOrEmpty(contentType.Name))
                        ListUtil.AddCTypeByName(list, contentType.Name);
            }

            list.Update();
        }
    }

    public class RemoveCTypes
        : ListCTypeOperation
    {
        public override void Execute(SPWeb web, SPList list)
        {
            foreach (ContentTypeRef contentType in ContentTypes)
            {
                ListUtil.RemoveCType(list, contentType.ID);
            }

            list.Update();
        }
    }

    public class ReorderCTypes
        : ListOperation
    {
        public override void Execute(SPWeb web, SPList list)
        {
            ListUtil.ReorderCTypes(list);
        }
    }

    public class PrincipalListRole
    {
        private string role;
        private string name;
        private string action;
        private string type;

        [XmlAttribute()]
        public string Role
        {
            get { return role; }
            set { role = value; }
        }

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlAttribute()]
        public string Action
        {
            get { return action; }
            set { action = value; }
        }

        [XmlAttribute()]
        public string Type
        {
            get { return type; }
            set { type = value; }
        }

        public void Process(SPWeb web, SPList list)
        {
            name = ParserUtil.ReplaceLiveFields(name, list, web);

            DoSecurityActions(list, web);
        }

        protected void DoSecurityActions(SPSecurableObject securableObject, SPWeb web)
        {
            bool doAdd = action == "Add";
            bool doRemove = action == "Remove";

            if (!doAdd && !doRemove)
            {
                Logger.Info("Unsupported action attribute: " + action);
                return;
            }
            
            //SPPrincipal principal = null;

            PSAcl acl = new PSAcl(securableObject, web);

            switch (type)
            {
                case "SiteGroup":
                {
                    if(doAdd)
                       acl.AddSiteGroup(name, role);
                    else 
                        acl.RemoveSiteGroup(name, null);

                    break;
                }

                case "User":
                {
                    if (doAdd)
                        acl.AddUser(name, role);
                    else
                        acl.RemoveUser(name, null);

                    break;
                }

                default:
                    Logger.Info("Unsupported principal type : " + type);
                    break;
            }

            //if (principal != null)
            //{
            //    if (doAdd)
            //        AclUtil.AddPrincipal(principal, role, securableObject, web);
            //    else
            //    {
            //        AclUtil.RemovePrincipal(principal, securableObject, web);
            //    }
            //}
        }
    }

    public class FixupACL
        : ListOperation
    {
        private string roleAssignments;
        private List<PrincipalListRole> roles = new List<PrincipalListRole>();

        [XmlAttribute()]
        public string RoleAssignments
        {
            get { return roleAssignments; }
            set { roleAssignments = value; }
        }

        [XmlElement("PrincipalRole")]
        public List<PrincipalListRole> Roles
        {
            get { return roles; }
            set { roles = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            Logger.Info("Configuring list ACL: " + list.Title);

            if (!string.IsNullOrEmpty(RoleAssignments))
            {
                if (RoleAssignments.StartsWith("Break") && !list.HasUniqueRoleAssignments)
                {
                    Logger.Info("Breaking role inheritance: " + RoleAssignments);
                    list.BreakRoleInheritance(RoleAssignments == "BreakAndCopy");
                }
            }

            foreach (PrincipalListRole principalRole in Roles)
            {
                principalRole.Process(web, list);
            }

            web.Update();
        }
    }

    public class LessField
    {
        private string name;

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }

    public class InjectCTypeFields
    {
        private int position;
        private List<LessField> fields = new List<LessField>();

        [XmlAttribute()]
        public int Position
        {
            get { return position; }
            set { position = value; }
        }

        [XmlElement("LessField")]
        public List<LessField> Fields
        {
            get { return fields; }
            set { fields = value; }
        }

        public void Process(SPView view, SPList list)
        {
            if (Position > view.ViewFields.Count)
                Position = view.ViewFields.Count;

            StringCollection less = new StringCollection();
            foreach (LessField lessField in fields)
            {
                less.Add(lessField.Name);
            }

            ListUtil.InjectFieldsFromCTypes(view, list.ContentTypes, Position, less);
        }
    }

    public class ViewField
    {
        private string name;

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }

    public class InjectViewFields
    {
        private List<ViewField> viewFields = new List<ViewField>();

        [XmlElement("ViewField")]
        public List<ViewField> ViewFields
        {
            get { return viewFields; }
            set { viewFields = value; }
        }

        public void Process(SPView view, SPList list)
        {
            view.ViewFields.DeleteAll();
            foreach (ViewField viewField in ViewFields)
            {
                view.ViewFields.Add(viewField.Name);
            }
            view.Update();
        }
    }

    public class FixupView
        : ListOperation
    {
        private string name;
        private List<InjectCTypeFields> injectTypes = new List<InjectCTypeFields>();
        private List<InjectViewFields> injectViewFields = new List<InjectViewFields>();

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlElement("InjectCTypeFields")]
        public List<InjectCTypeFields> InjectTypes
        {
            get { return injectTypes; }
            set { injectTypes = value; }
        }

        [XmlElement("InjectViewFields")]
        public List<InjectViewFields> InjectFields
        {
            get { return injectViewFields; }
            set { injectViewFields = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            if(!string.IsNullOrEmpty(Name))
            {
                SPView view = list.Views[Name];
                if (view != null)
                {
                    foreach (InjectCTypeFields injectType in injectTypes)
                    {
                        injectType.Process(view, list);
                    }
                    foreach (InjectViewFields injectField in injectViewFields)
                    {
                        injectField.Process(view, list);
                    }
                }

            }
        }
    }

    public class FieldChoices
    {
        private bool flush;
        private List<string> choices = new List<string>();

        [XmlAttribute()]
        public bool Flush
        {
            get { return flush; }
            set { flush = value; }
        }

        // TODO: check deserialization
        [XmlElement("Choice")]
        public List<string> Choices
        {
            get { return choices; }
            set { choices = value; }
        }
    }

    public class UpdateField
    {
        private string displayName;
        private string staticName;
        private string description;
        private bool dumpFields;
        private bool linkToLocalCTypes;
        private string defaultValue;
        private FieldChoices choices;

        [XmlAttribute()]
        public string DisplayName
        {
            get { return displayName; }
            set { displayName = value; }
        }

        [XmlAttribute()]
        public string StaticName
        {
            get { return staticName; }
            set { staticName = value; }
        }

        public string Description
        {
            get { return description; }
            set { description = value; }
        }

        public bool DumpFields
        {
            get { return dumpFields; }
            set { dumpFields = value; }
        }

        [XmlAttribute()]
        public bool LinkToLocalCTypes
        {
            get { return linkToLocalCTypes; }
            set { linkToLocalCTypes = value; }
        }

        public FieldChoices Choices
        {
            get { return choices; }
            set { choices = value; }
        }

        // TODO : check deserialization
        public string Default
        {
            get { return defaultValue; }
            set { defaultValue = value; }
        }

        public void Process(SPWeb web, SPList list)
        {
            if (string.IsNullOrEmpty(DisplayName) && string.IsNullOrEmpty(StaticName))
                return;

            SPField field = null;
            try
            {
                if (!string.IsNullOrEmpty(StaticName))
                    field = list.Fields.GetFieldByInternalName(StaticName);
                else
                    field = list.Fields[DisplayName];
            }
            catch (ArgumentException)
            {
            }

            if (field == null)
            {
                Logger.Info("Could not find field " + DisplayName + ":" + StaticName+ " in list " + list.Title);
                return;
            }

            Logger.Info("Updating field " + field.StaticName + " in list " + list.Title + ". ID=" + field.Id + ", SourceID=" + field.SourceId);

            if (field.Sealed)
            {
                field.Sealed = false;
                Logger.Info("Field was sealed");
            }

            if(Description != null)
            {
                field.Description = ParserUtil.ReplaceLiveFields(Description, list, web);
                Logger.Info("Description set to: " + field.Description);
            }

            if(DumpFields)
            {
                foreach (SPField spField in list.Fields)
                {
                    Logger.Info(list.Title + ": {" + spField.Id + "} -- " + spField.StaticName + " : " + spField.Title);
                }
            }

            if(LinkToLocalCTypes)
            {
                Logger.Info("Adding field " + field.StaticName + " to all local list content types ");
                ListUtil.LinkFieldToListCTypes(field, list);
            }

            SPFieldChoice choice = field as SPFieldChoice;
            SPFieldMultiChoice mchoice = field as SPFieldMultiChoice;
            
            if (choice != null || mchoice != null)
            {
                if(Choices != null)
                {
                    StringBuilder sb = new StringBuilder();
                    StringCollection coll = choice != null ? choice.Choices : mchoice.Choices;
                    if (Choices.Flush)
                    {
                        coll.Clear();
                        sb.Append("#Flush# ");
                    }

                    foreach (string fieldChoise in Choices.Choices)
                    {
                        string s = ParserUtil.ReplaceLiveFields(fieldChoise, list, web);
                        sb.Append(s + "; ");
                        coll.Add(s);
                    }

                    Logger.Info("Choices added: " + sb);
                }
            }

            if (Default != null)
            {
                string prevDef = field.DefaultValue;
                string curDef = ParserUtil.ReplaceLiveFields(Default, list, web);
                field.DefaultValue = curDef;

                Logger.Info("Default value of '" + prevDef + "' replaced with '" + field.DefaultValue + "'");
            }

            field.Update(true);
        }
    }

    public class UpdateFields
        : ListOperation
    {
        private List<UpdateField> fields = new List<UpdateField>();

        [XmlElement("Field")]
        public List<UpdateField> Fields
        {
            get { return fields; }
            set { fields = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            try
            {
                foreach (UpdateField field in Fields)
                {
                    field.Process(web, list);
                }
            }
            catch (Exception e)
            {
                Logger.Info("Exception occured while updating fields");
                Logger.Error(e);
            }

            list.Update();
        }
    }

    // TODO : ensure correct deserialization
    public class AddField
    {
        private string field;
        private bool addToDefaultView;

        [XmlText()]
        public string Field
        {
            get { return field; }
            set { field = value; }
        }

        [XmlAttribute()]
        public bool AddToDefaultView
        {
            get { return addToDefaultView; }
            set { addToDefaultView = value; }
        }
    }

    public class AddFields
        : ListOperation
    {
        private List<AddField> fields = new List<AddField>();

        [XmlElement("Field")]
        public List<AddField> Fields
        {
            get { return fields; }
            set { fields = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            try
            {
                foreach (AddField field in Fields)
                {
                    Logger.Info("Adding field: " + field.Field);
                    list.Fields.AddFieldAsXml(field.Field, field.AddToDefaultView, SPAddFieldOptions.AddToAllContentTypes);
                    list.Update();
                }
            }
            catch (Exception e)
            {
                Logger.Info("Exception occured while adding fields");
                Logger.Error(e);
            }
        }
    }

    public class ItemColumn
    {
        private string fieldName;
        private string fieldValue;

        [XmlAttribute()]
        public string FieldName
        {
            get { return fieldName; }
            set { fieldName = value; }
        }

        [XmlText()]
        public string Value
        {
            get { return fieldValue; }
            set { this.fieldValue = value; }
        }
    }

    public class ListItem : ListOperation
    {
        private string type;
        private string name;
        private int id = -1;
        private FixupItemACL fixupItemACL;
        private FileStatus fileStatus;
        private List<ItemColumn> columns = new List<ItemColumn>();
        private bool syncWithPropertyBag = false;

        [XmlElement("Column")]
        public List<ItemColumn> Columns
        {
            get { return columns; }
            set { columns = value; }
        }

        [XmlElement]
        public FileStatus FileStatus
        {
            get { return fileStatus; }
            set { fileStatus = value; }
        }

        [XmlAttribute()]
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        [XmlElement("FixupACL")]
        public FixupItemACL FixupItemACL
        {
            get { return fixupItemACL; }
            set { fixupItemACL = value; }
        }

        [XmlAttribute()]
        public int ID
        {
            get { return id; }
            set { id = value; }
        }

        [XmlAttribute()]
        public string Type
        {
            get { return type; }
            set { type = value; }
        }

        [XmlAttribute()]
        public bool SyncWithPropertyBag
        {
            get { return syncWithPropertyBag; }
            set { syncWithPropertyBag = value; }
        }

        public override void Execute(SPWeb web, SPList list)
        {
            if((SyncWithPropertyBag) || Columns.Count > 0)
            {
                SPListItem item = list.Items.Add();

                // Add text columns based on property bag key/value pairs
                if(SyncWithPropertyBag)
                {
                    foreach(var prop in ParserUtil.GetProvisionedProperties(web))
                    {
                        ListUtil.EnsureListField(list, prop.Key);
                        item[prop.Key] = prop.Value;
                    }
                    item.Update();
                }

                // Set up explicitely declared columns
                if(Columns.Count > 0)
                {
                    Dictionary<string, string> columnDictionary = columns.ToDictionary(
                        col => col.FieldName, 
                        col => ParserUtil.ReplaceAllLiveFields(col.Value, list.ParentWeb));

                    foreach (var col in columnDictionary)
                    {
                        ListUtil.EnsureListField(list, col.Key);
                        item[col.Key] = col.Value;
                    }

                    item.Update();
                }
            }

            switch(Type)
            {
                case "Folder":
                {
                    //Thread.Sleep(300000);
                    ProcessFolder(list, web);
                    break;
                }

                case "File":
                {
                    ProcessFile(list, web);
                    break;
                }

                case "Item":
                {
                    ProcessItem(list, web);
                    break;                   
                }

                default:
                    break;
            }
        }

        private void ProcessItem(SPList list, SPWeb web)
        {
            if (ID > 0)
            {
                try
                {
                    SPListItem listItem = list.Items.GetItemById(ID);
                    if (listItem != null)
                    {
                        FixupItemACL.Execute(web, list, listItem);
                    }
                }
                catch(ArgumentException )
                {}
            }
        }

        private void ProcessFile(SPList list, SPWeb web)
        {
            if (!string.IsNullOrEmpty(Name))
            {
                foreach(SPListItem item in list.Items)
                if (item.File != null && item.File.Name == name)
                {
                    if (FixupItemACL != null)
                    FixupItemACL.Execute(web, list, item);

                    if (fileStatus != null)
                        fileStatus.Execute(web, item.File);
                }
            }
        }

        private void ProcessFolder(SPList list, SPWeb web)
        {
            if (!string.IsNullOrEmpty(Name))
            {

                 foreach (SPListItem listItem in list.Folders)
                {
                    SPFolder folder = listItem.Folder;
                    if (folder != null && folder.Name == Name && folder.Item != null)
                    {
                        FixupItemACL.Execute(web, list, folder.Item);
                        break;
                    }
                }
            }
        }
    }

    public class FileStatus
    {
 
        public enum Status
        {
            CheckIn, CheckOut, Publish
        }

        private Status status;

        [XmlAttribute]
        public Status SetStatus
        {
            get { return status; }
            set { status = value; }
        }

        public void Execute(SPWeb web, SPFile spFile)
        {
            if (spFile != null)
            {
                Logger.Info("Setting Item Status: " + spFile.Name);

                try
                {
                    switch (status)
                    {
                        case Status.CheckOut:
                            spFile.CheckOut();
                            break;
                        case Status.CheckIn:
                            spFile.CheckIn(string.Empty);
                            break;
                        case Status.Publish:
                            try
                            {
                                spFile.CheckIn(string.Empty);
                            }
                            catch (SPException)
                            {
                            }
                            spFile.Publish(string.Empty);
                            try
                            {
                                spFile.Approve(string.Empty);
                            }catch(SPException)
                            {
                            }
                            break;
                    }

                    spFile.Update();
                }
                catch (SPException)
                {
                }
            }
        }      
    }

    public class FixupItemACL
    {
        private string roleAssignments;
        private List<PrincipalItemRole> principalItemRoles;

        [XmlAttribute()]
        public string RoleAssignments
        {
            get { return roleAssignments; }
            set { roleAssignments = value; }
        }

        [XmlElement("PrincipalRole")]
        public List<PrincipalItemRole> PrincipalItemRoles
        {
            get { return principalItemRoles; }
            set { principalItemRoles = value; }
        }

        public void Execute(SPWeb web, SPList spList, SPListItem listItem)
        {
            Logger.Info("Configuring folder ACL: " + listItem.Name);

            if (!string.IsNullOrEmpty(RoleAssignments))
            {
                if (RoleAssignments.StartsWith("Break") && !listItem.HasUniqueRoleAssignments)
                {
                    Logger.Info("Breaking role inheritance: " + RoleAssignments);
                    listItem.BreakRoleInheritance(RoleAssignments == "BreakAndCopy");
                }
            }

            foreach (PrincipalItemRole principalItemRole in PrincipalItemRoles)
            {
                principalItemRole.Execute(web, spList, listItem);
            }

            web.Update();
        }
    }

    public class PrincipalItemRole :  PrincipalListRole
    {
        public void Execute(SPWeb web, SPList spList, SPListItem listItem)
        {
            this.Name = ParserUtil.ReplaceLiveFields(this.Name, spList, web);
                        
            if (listItem != null)
            {
                DoSecurityActions(listItem, web);
            }
            else
            {
                Logger.Info("Folder item cannot be null, list: " + spList.Title);
            }
        }
    }
}
